package com.xuecheng.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xuecheng.base.execption.XueChengPlusException;
import com.xuecheng.model.PageParams;
import com.xuecheng.search.dto.SearchCourseParamDto;
import com.xuecheng.search.dto.SearchPageResultDto;
import com.xuecheng.search.po.CourseIndex;
import com.xuecheng.search.service.CourseSearchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.lucene.search.TotalHits;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MultiMatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author Mr.M
 * @version 1.0
 * @description 课程搜索service实现类
 * @date 2022/9/24 22:48
 */
@Slf4j
@Service
public class CourseSearchServiceImpl implements CourseSearchService {

    @Value("${elasticsearch.course.index}")
    private String courseIndexStore;
    @Value("${elasticsearch.course.source_fields}")
    private String sourceFields;

    @Autowired
    RestHighLevelClient client;

    /**
     * 课程搜索接口
     * @param pageParams 分页参数
     * @param searchCourseParamDto 搜索条件
     * @return
     */
    @Override
    public SearchPageResultDto<CourseIndex> queryCoursePubIndex(PageParams pageParams, SearchCourseParamDto searchCourseParamDto) {
        //创建request
        SearchRequest request = new SearchRequest(courseIndexStore);
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //准备bool查询
        BoolQueryBuilder bool = QueryBuilders.boolQuery();

        //配置需要的字段，默认是全部字段
        String[] split = sourceFields.split(",");
        searchSourceBuilder.fetchSource(split,new String[]{});//searchSourceBuilder.fetchSource(需要的字段，排除的字段)

        if(searchCourseParamDto==null){
            searchCourseParamDto=new SearchCourseParamDto();
        }

        //匹配关键字
        if(!StringUtils.isEmpty(searchCourseParamDto.getKeywords())){
            MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(searchCourseParamDto.getKeywords(), "name", "description");//一个关键字对应多个字段
            //设置匹配占比
            multiMatchQueryBuilder.minimumShouldMatch("70%");
            //提升另个字段的Boost值
            multiMatchQueryBuilder.field("name",10);
            //must必须包含
            bool.must(multiMatchQueryBuilder);
        }
        //匹配大分类
        if(!StringUtils.isEmpty(searchCourseParamDto.getMt())){
            //termQuery用于精准，matchQuery用于文本字段
            bool.filter(QueryBuilders.termQuery("mtName",searchCourseParamDto.getMt()));
        }
        //匹配小分类
        if(!StringUtils.isEmpty(searchCourseParamDto.getSt())){
            bool.filter(QueryBuilders.termQuery("stName",searchCourseParamDto.getSt()));
        }
        //匹配难度
        if(!StringUtils.isEmpty(searchCourseParamDto.getGrade())){
            bool.filter(QueryBuilders.termQuery("grade",searchCourseParamDto.getGrade()));
        }

        //将bool查询的条件并入searchSourceBuilder
        searchSourceBuilder.query(bool);
        //分页查询
        searchSourceBuilder.from((int) ((pageParams.getPageNo()-1)*pageParams.getPageSize()));
        searchSourceBuilder.size(Math.toIntExact(pageParams.getPageSize()));

        //构建高亮查询的字段
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<font class='eslight'>");//设置标签前缀
        highlightBuilder.postTags("</font>");//设置标签后缀
        highlightBuilder.field("name");//设置高亮字段
        /* 多个高亮字段
        HighlightBuilder.Fields fieldsHighlightBuilder = highlightBuilder.fields();
        fieldsHighlightBuilder.add(new HighlightBuilder.Field("name")
            // 这里可以添加额外的配置，比如前缀、后缀、片段大小等
            .preTags("<em>").postTags("</em>")
            .fragmentSize(50));

        // 继续添加其他字段
        fieldsHighlightBuilder.add(new HighlightBuilder.Field("description")
            .preTags("<strong>").postTags("</strong>")
            .fragmentSize(100));
         */
        //设置高亮构建对象
        searchSourceBuilder.highlighter(highlightBuilder);


        //设置请求体
        request.source(searchSourceBuilder);
        //聚合设置
        buildAggregation(request);
        SearchResponse search = null;
        try{
            search = client.search(request, RequestOptions.DEFAULT);
        }catch (Exception e){
            e.printStackTrace();
            log.info("课程搜索异常：{}",e.getMessage());
            XueChengPlusException.cast("课程搜索异常");
        }

        //进行结果解析
        SearchHits hits = search.getHits();
        //总数
        Long counts = hits.getTotalHits().value;
        //数据列表
        ArrayList<CourseIndex> courseIndices = new ArrayList<>();
        SearchHit[] hitsHits = hits.getHits();
        for (SearchHit hitsHit : hitsHits) {
            //解析出具体的数据
            String sourceAsString = hitsHit.getSourceAsString();
            //将其转换为对象
            CourseIndex courseIndex = JSON.parseObject(sourceAsString, CourseIndex.class);


            //课程id
            Long id = courseIndex.getId();
            //取出名称
            String name = courseIndex.getName();
            //取出高亮字段内容
            Map<String, HighlightField> highlightFields = hitsHit.getHighlightFields();
            if(highlightFields!=null){

                HighlightField nameField = highlightFields.get("name");
                if(nameField!=null){
                    // 获取高亮字段的所有片段（fragments）
                    Text[] fragments = nameField.getFragments();
                    // 使用 StringBuffer 来拼接所有片段的内容
                    StringBuffer stringBuffer = new StringBuffer();
                    for (Text str : fragments) {
                        stringBuffer.append(str.string());
                    }
                    name = stringBuffer.toString();
                }
            }
            courseIndex.setId(id);
            courseIndex.setName(name);

            courseIndices.add(courseIndex);
        }
        SearchPageResultDto<CourseIndex>  pageResult = new SearchPageResultDto<>(courseIndices, counts, pageParams.getPageNo(), pageParams.getPageSize());

        //获取聚合结果
        List<String> mtList= getAggregation(search.getAggregations(), "mtAgg");
        List<String> stList = getAggregation(search.getAggregations(), "stAgg");

        pageResult.setMtList(mtList);
        pageResult.setStList(stList);
        return pageResult;
    }

    private List<String> getAggregation(Aggregations aggregations, String mtAgg) {
        //获取mtAgg下的数据
        Terms terms=aggregations.get(mtAgg);
        List<? extends Terms.Bucket> buckets = terms.getBuckets();
        List<String> brandList = new ArrayList<>();
        for (Terms.Bucket bucket : buckets) {
            // 4.4.获取key
            String key = bucket.getKeyAsString();
            brandList.add(key);
        }
        return brandList;
    }

    private void buildAggregation(SearchRequest request) {
        request.source().aggregation(AggregationBuilders
                .terms("mtAgg")
                .field("mtName")
                .size(100)
        );
        request.source().aggregation(AggregationBuilders
                .terms("stAgg")
                .field("stName")
                .size(100)
        );

    }

//    @Override
//    public SearchPageResultDto<CourseIndex> queryCoursePubIndex(PageParams pageParams, SearchCourseParamDto courseSearchParam) {
//
//        //设置索引
//        SearchRequest searchRequest = new SearchRequest(courseIndexStore);
//
//        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//        //source源字段过虑
//        String[] sourceFieldsArray = sourceFields.split(",");
//        searchSourceBuilder.fetchSource(sourceFieldsArray, new String[]{});
//        if(courseSearchParam==null){
//            courseSearchParam = new SearchCourseParamDto();
//        }
//        //关键字
//        if(StringUtils.isNotEmpty(courseSearchParam.getKeywords())){
//            //匹配关键字
//            MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery(courseSearchParam.getKeywords(), "name", "description");
//            //设置匹配占比
//            multiMatchQueryBuilder.minimumShouldMatch("70%");
//            //提升另个字段的Boost值
//            multiMatchQueryBuilder.field("name",10);
//            boolQueryBuilder.must(multiMatchQueryBuilder);
//        }
//        //过虑
//        if(StringUtils.isNotEmpty(courseSearchParam.getMt())){
//            boolQueryBuilder.filter(QueryBuilders.termQuery("mtName",courseSearchParam.getMt()));
//        }
//        if(StringUtils.isNotEmpty(courseSearchParam.getSt())){
//            boolQueryBuilder.filter(QueryBuilders.termQuery("stName",courseSearchParam.getSt()));
//        }
//        if(StringUtils.isNotEmpty(courseSearchParam.getGrade())){
//            boolQueryBuilder.filter(QueryBuilders.termQuery("grade",courseSearchParam.getGrade()));
//        }
//        //分页
//        Long pageNo = pageParams.getPageNo();
//        Long pageSize = pageParams.getPageSize();
//        int start = (int) ((pageNo-1)*pageSize);
//        searchSourceBuilder.from(start);
//        searchSourceBuilder.size(Math.toIntExact(pageSize));
//        //布尔查询
//        searchSourceBuilder.query(boolQueryBuilder);
//        //高亮设置
//        HighlightBuilder highlightBuilder = new HighlightBuilder();
//        highlightBuilder.preTags("<font class='eslight'>");
//        highlightBuilder.postTags("</font>");
//        //设置高亮字段
//        highlightBuilder.fields().add(new HighlightBuilder.Field("name"));
//        searchSourceBuilder.highlighter(highlightBuilder);
//        //请求搜索
//        searchRequest.source(searchSourceBuilder);
//        //聚合设置
//        buildAggregation(searchRequest);
//        SearchResponse searchResponse = null;
//        try {
//            searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
//        } catch (IOException e) {
//            e.printStackTrace();
//            log.error("课程搜索异常：{}",e.getMessage());
//            return new SearchPageResultDto<CourseIndex>(new ArrayList(),0,0,0);
//        }
//
//        //结果集处理
//        SearchHits hits = searchResponse.getHits();
//        SearchHit[] searchHits = hits.getHits();
//        //记录总数
//        TotalHits totalHits = hits.getTotalHits();
//        //数据列表
//        List<CourseIndex> list = new ArrayList<>();
//
//        for (SearchHit hit : searchHits) {
//
//            String sourceAsString = hit.getSourceAsString();
//            CourseIndex courseIndex = JSON.parseObject(sourceAsString, CourseIndex.class);
//
//            //取出source
//            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
//
//            //课程id
//            Long id = courseIndex.getId();
//            //取出名称
//            String name = courseIndex.getName();
//            //取出高亮字段内容
//            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
//            if(highlightFields!=null){
//                HighlightField nameField = highlightFields.get("name");
//                if(nameField!=null){
//                    Text[] fragments = nameField.getFragments();
//                    StringBuffer stringBuffer = new StringBuffer();
//                    for (Text str : fragments) {
//                        stringBuffer.append(str.string());
//                    }
//                    name = stringBuffer.toString();
//
//                }
//            }
//            courseIndex.setId(id);
//            courseIndex.setName(name);
//
//            list.add(courseIndex);
//
//        }
//        SearchPageResultDto<CourseIndex> pageResult = new SearchPageResultDto<>(list, totalHits.value,pageNo,pageSize);
//
//        //获取聚合结果
//        List<String> mtList= getAggregation(searchResponse.getAggregations(), "mtAgg");
//        List<String> stList = getAggregation(searchResponse.getAggregations(), "stAgg");
//
//        pageResult.setMtList(mtList);
//        pageResult.setStList(stList);
//
//        return pageResult;
//    }
//
//
//    private void buildAggregation(SearchRequest request) {
//        request.source().aggregation(AggregationBuilders
//                .terms("mtAgg")
//                .field("mtName")
//                .size(100)
//        );
//        request.source().aggregation(AggregationBuilders
//                .terms("stAgg")
//                .field("stName")
//                .size(100)
//        );
//
//    }
//
//    private List<String> getAggregation(Aggregations aggregations, String aggName) {
//        // 4.1.根据聚合名称获取聚合结果
//        Terms brandTerms = aggregations.get(aggName);
//        // 4.2.获取buckets
//        List<? extends Terms.Bucket> buckets = brandTerms.getBuckets();
//        // 4.3.遍历
//        List<String> brandList = new ArrayList<>();
//        for (Terms.Bucket bucket : buckets) {
//            // 4.4.获取key
//            String key = bucket.getKeyAsString();
//            brandList.add(key);
//        }
//        return brandList;
//    }
}
